const EventBus = require("./event-bus.js");

class EventStore {
  constructor(option) {
    if (!this._isObject(option.state)) {
      throw new Error("参数必须是一个对象");
    }
    this.state = option.state; // 状态

    if (option.action && this._isObject(option.action)) {
      const values = Object.values(option.action);
      for (const value of values) {
        if (!value instanceof Function) {
          throw new Error("action必须是一个函数");
        }
      }
      this.action = option.action; // 动作
    }
    this.eventBus = new EventBus();
    this.eventBusV2 = new EventBus();
    this.proxy = this._observe(); // 监听
  }

  _observe() {
    const _this = this;
    const proxy = new Proxy(_this.state, {
      get(target, key, receiver) {
        return Reflect.get(target, key, receiver);
      },
      set(target, key, value, receiver) {
        _this.eventBus.emit(key, value);
        _this.eventBusV2.emit(key, { [key]: value });
        return Reflect.set(target, key, value, receiver);
      },
    });

    return proxy;
  }

  onStateChange(key, callback) {
    const keys = Object.keys(this.state);
    if (!keys.includes(key)) {
      throw new Error("key not found");
    }
    this.eventBus.on(key, callback);
    callback.apply(this.proxy, [this.proxy[key]]);
  }

  onStateChanges(stateKeys, callback) {
    const keys = Object.keys(this.state);
    const value = {};
    for (const item of stateKeys) {
      if (!keys.includes(item)) {
        throw new Error("key not found");
      }
      this.eventBusV2.on(item, callback);
      value[item] = this.proxy[item];
    }
    callback.apply(this.proxy, [value]);
  }

  onceStateChange(key, callback) {
    const keys = Object.keys(this.state);
    if (!keys.includes(key)) {
      throw new Error("key not found");
    }
    this.eventBus.once(key, callback);
    callback.apply(this.proxy, [this.proxy[key]]);
  }

  setStateChange(key, value) {
    const keys = Object.keys(this.state);
    if (!keys.includes(key)) {
      throw new Error("key not found");
    }
    this.proxy[key] = value;
  }

  dispatch(actionName, ...args) {
    const action = this.action[actionName];
    if (typeof action !== "function") {
      throw new Error("action not found");
    }
    action.apply(this, [this.proxy, ...args]);
  }

  offStateChange(key, callback) {
    const keys = Object.keys(this.state);
    if (!keys.includes(key)) {
      throw new Error("key not found");
    }
    this.eventBus.off(key, callback);
  }

  offStateChanges(stateKeys, callback) {
    const keys = Object.keys(this.state);
    for (const key of stateKeys) {
      if (!keys.includes(key)) {
        throw new Error("key not found");
      }
      this.eventBusV2.off(key, callback);
    }
  }

  _isObject(obj) {
    return typeof obj === "object" && obj !== null;
  }
}

const store = new EventStore({
  state: {
    count: 0,
    name: "zhangsan",
  },
  action: {
    add(state, payload) {
      this.setStateChange("count", this.state.count + 13);
      this.setStateChange("name", "lisi");
      // state.count += 22;
      // state.name = "lisi";
    },
    minus(state, payload) {
      state.count -= 22;
    },
  },
});

const fn = (value) => {
  console.log("count changed", value);
};

store.onStateChange("name", fn);

store.dispatch("add", "hello");
